package com.wangzhenyu.learn.test.designPattern


//职责链模式

@Suppress("UNUSED")
object XChainOfResponsibilityPattern {

    data class ApplyEvent(val money: Int, val title: String)

    class ChainOfResponsibility<in T, out R>(
        private val defineAt: (T) -> Boolean,
        private val finally: (T) -> R
    ) : (T) -> R {

        companion object {

            fun test() {
                val applyChain = AType orElse BType orElse CType orElse DType
                applyChain(ApplyEvent(800, "目标"))
            }
        }

        override fun invoke(p1: T): R {
            if (defineAt(p1)) {
                return finally(p1)
            } else {
                throw IllegalArgumentException("value $p1 is not support bu this function")
            }
        }

        fun isDefinedAt(p1: T): Boolean = defineAt(p1)

    }

    infix fun <T, R> ChainOfResponsibility<T, R>.orElse(that: ChainOfResponsibility<T, R>): ChainOfResponsibility<T, R> {
        return ChainOfResponsibility({ this.isDefinedAt(it) || that.isDefinedAt(it) }) {
            if (this.isDefinedAt(it)) this(it) else that(it)
        }
    }

    val AType = run {
        val defineAt: (ApplyEvent) -> Boolean = {
            println("A")
            it.money < 200
        }
        val finally: (ApplyEvent) -> Unit = {
            println("该数据处于A中")
        }
        ChainOfResponsibility(defineAt, finally)
    }

    val BType = run {
        val defineAt: (ApplyEvent) -> Boolean = {
            println("B")
            it.money < 500
        }
        val finally: (ApplyEvent) -> Unit = {
            println("该数据处于B中")
        }
        ChainOfResponsibility(defineAt, finally)
    }

    val CType = run {
        val defineAt: (ApplyEvent) -> Boolean = {
            println("C")
            it.money < 1000
        }
        val finally: (ApplyEvent) -> Unit = {
            println("该数据处于C中")
        }
        ChainOfResponsibility(defineAt, finally)
    }

    val DType = run {
        val defineAt: (ApplyEvent) -> Boolean = {
            println("D")
            it.money < 2000
        }
        val finally: (ApplyEvent) -> Unit = {
            println("该数据处于D中")
        }
        ChainOfResponsibility(defineAt, finally)
    }

}